home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
ab20
/
ab20_archive
/
datacomm
/
xpr
/
xprkermit-1.111.lzh
/
xprkermit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-27
|
25KB
|
934 lines
/** xprkermit.c
*
* $Log: xprkermit.c,v $
* Revision 1.3 91/11/09 06:53:22 swalton
* Added support for re-entrant library, by cloning the data segment on entrance
* to the protocol. This is something of a trick which depends heavily on
* the particular way Aztec C organizes small model segments, but it seems
* to work fine.
*
*
* These are the protocol transfer routines for a simple Kermit upload/dnload
*
* Version 0.9--by Marco Papa.
*
* Version 1.0--updated by Stephen Walton.
* Added several more user selections to XPRotocolSetup():
* bctr (block check type to request), limit (retry-limit), and
* rtimo (timeout for me). "Real" C Kermit makes many of the
* things declared as local to kermitproto.w user-settable,
* such as the send packet size.
* Also fixed several problems in kermitproto.w.
*
* Version 1.5--more features
* Extensive changes.
* (1) Created a SetupVars variable to hold setting-up information
* in the XPR_IO structure. This will allow re-entrancy when and if
* it comes. Right now, it mainly gives a way to set up defaults with
* one assignment.
* (2) Added the generic Kermit server functions FINISH, BYE, and CD.
* (3) Added the ability to set options and execute the server functions
* from a setup string (sent as IO->xpr_filename to XPRotocolSetup()).
*
* Version 1.6
* Some changes to the chkint() code in kermitproto.w to allow better
* file cancellations. In particular, -1 is returned if the user
* does the maximum XPR abort.
*
* Bug fixed in malloc() in this module: it wasn't saving the correct
* number of allocated characters.
*
* Version 1.61
* More mucking with chkint(). Irrelevant to VLT at present.
*
* Version 1.62
* "Final" version of interrupt code. Based on C Kermit, if chkint()
* returns a negative number, I both put "User cancelled." on the
* display and send it in an error packet to the other end.
*
* Version 1.63
* gnchar() in kermitproto.w wasn't counting nulls! Fixed.
*
* This code is copyright 1990 by Stephen Walton and Marco Papa. It may
* be freely distributed in its original or in modified form, provided
* this copyright notice is kept intact. It may not be sold for profit,
* but may be included as part of a commercial program provided that
* said inclusion does not increase the cost of that program beyond a
* modest handling fee.
**/
#ifndef _lint
static char rcsid[] = "$Header: Work:src/xprkermit/RCS/xprkermit.c,v 1.3 91/11/09 06:53:22 swalton Exp Locker: swalton $";
#endif
#include <exec/memory.h>
#include <functions.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* xproto.h is the include file given in Appendix B. It is included
* in xprkermit.h
*/
#include "xprkermit.h"
#include "kermitproto.h"
#include "timer.h"
#include "version.h"
long (*xupdate) (), (*xswrite) (), (*xfopen) (), (*xfclose) (), (*xfread) (),
(*xsread) (), (*xchkabort) (), (*xfnext) (), (*xffirst) (), (*xsflush) (),
(*xfwrite) (), (*xgets) (), (*xfinfo) (), (*xunlink)() ,
(*xsquery) (), (*xchkmisc) ();
extern CHAR start; /* The start state for the protocol. */
/*
* Forward declarations
*/
static SetupVars *setup(struct XPR_IO *IO);
/*
* The flags for the kermitproto.w module.
*/
char *p_pattern; /* wildcard pattern */
int parity; /* parity on? 0 for no parity--need for
* proper 8th-bit quote */
int text; /* Text or binary mode? Flag 1 for text file,
* 0 for binary file */
int convert; /* Convert file names to lower case? 0 for
* literal files (no), 1 for translate (yes) */
int urpsiz; /* Kermit maximum packet size. Maximum
* receive packet size user wants. */
char *cmarg; /* Character string containing Kermit server
* cmd */
extern int bctr; /* Block check type to request. */
extern int limit; /* Retry limit. May increase on very noisy
* lines. */
extern int rtimo; /* Timeout to request. */
extern int keep; /* Keep incomplete files? */
int getfile; /* Host server. 0 = Receive (no) ; 1 = Get
* (yes) */
long brkflag;
static SetupVars Defaults = {
0L, /* Data segment--to be filled in later */
{""}, /* No default file name. */
0, /* Parity defaults to off. */
1, /* Text file defaults to on. */
1, /* Convert file names by default. */
94, /* Default maximum packet length. */
1, /* Default block check type. */
5, /* Retry limit */
10, /* Timeout (seconds) */
0, /* Don't keep incomplete files */
0, /* Host is server? No by default. */
};
/*
* Local prototypes.
*/
static KermitCd(struct XPR_IO *IO, char *dir);
static KermitFinish(struct XPR_IO *IO);
static KermitBye(struct XPR_IO *IO);
static DoGeneric(struct XPR_IO *IO, char *s);
/**
*
* Send a file
*
**/
long
XProtocolSend(IO)
struct XPR_IO *IO;
{
struct XPR_UPDATE xpru;
SetupVars *sv;
if ((sv = setup(IO)) == NULL)
return 0L; /* Initialize parameters. */
brkflag = 0;
/*
* Read the text/binary set using xpr_finfo if present. Else use the
* value chosen in XPRotocolSetup.
*/
if (xfinfo) {
/*
* Use feature that calling xpr_finfo with a zero-length filename
* returns setting of internal comm program Text/Binary flag.
*/
text = (callad(xfinfo, IO->xpr_filename, 2L) == 1 ? 0 : 1);
}
/*
* Start the transfer. See 3.8 for a discussion on how to implement
* xupdate.
*/
tchar('#');
/*
* Copy filename, and put pointer in external Kermit variable.
*/
strcpy(sv->FileName, IO->xpr_filename);
p_pattern = sv->FileName;
/*
* */
start = 's';
proto();
/*
* If we got here through chkabort() say Aborted.
*/
xpru.xpru_updatemask = XPRU_MSG;
if (brkflag)
xpru.xpru_msg = "Aborted";
else
xpru.xpru_msg = "Done";
(void) calla(xupdate, &xpru);
if (brkflag)
return (0L);
else
return (1L);
}
/**
*
* Receive a file.
*
**/
long
XProtocolReceive(IO)
struct XPR_IO *IO;
{
struct XPR_UPDATE xpru;
long status;
SetupVars *sv;
if ((sv = setup(IO)) == NULL)
return 0L; /* Initialize parameters. */
brkflag = 0;
/*
* Read the text/binary set using xpr_finfo if present. Else use the
* value chosen in XPRotocolSetup.
*/
if (xfinfo) {
/*
* Use feature th at calling xpr_finfo with a zero-length filename
* returns setting of internal comm program Text/Binary flag.
*/
text = (callad(xfinfo, "", 2L) == 1 ? 0 : 1);
}
/*
* Start the transfer. See 3.8 for a discussion on how to implement
* xupdate.
*/
tchar('#');
if (getfile) {
/*
* Copy filename, and put pointer in external Kermit variable.
*/
cmarg = sv->FileName;
start = 'r';
status = callaa(xgets, "Host Filename", cmarg);
if (!status)
return (0L);
} else
start = 'v';
proto();
/*
* If we got here through chkabort() say Aborted.
*/
xpru.xpru_updatemask = XPRU_MSG;
if (brkflag)
xpru.xpru_msg = "Aborted";
else
xpru.xpru_msg = "Done";
(void) calla(xupdate, &xpru);
if (brkflag)
return (0L);
else
return (1L);
}
/*
* Perform a generic Kermit server command.
*/
static
DoGeneric(IO, s)
struct XPR_IO *IO;
char *s;
{
if (setup(IO) == NULL)
return 0; /* Set up transfer characteristics. */
brkflag = 0;
start = 'g';
cmarg = s;
proto();
if (brkflag)
return (0);
else
return (1);
}
/*
* Execute a Kermit FINISH command.
*/
static
KermitFinish(IO)
struct XPR_IO *IO;
{
return (DoGeneric(IO, "F"));
}
/*
* Execute a Kermit BYE command.
*/
static
KermitBye(IO)
struct XPR_IO *IO;
{
return (DoGeneric(IO, "L"));
}
/*
* Change directory on remote server. We need to return an error if the CD
* fails on the remote end.
*/
static
KermitCd(IO, dir)
struct XPR_IO *IO;
char *dir;
{
char CdCommand[100];
int retval;
CdCommand[0] = 'C';
CdCommand[1] = (char) tochar(strlen(dir));
strcpy(CdCommand + 2, dir);
retval = DoGeneric(IO, CdCommand);
return retval;
}
/**
*
* Setup
*
* First, a general-purpose comparison for either of the two possible returns
* indicating a Yes push on a Boolean gadget.
**/
#define XprBoolTrue(s) ((stricmp(s, "yes") == 0) || (stricmp(s, "on") == 0))
/*
* Then, a small set of code to initialize a string based on a value.
*/
#define XprSet(value, string) ((value) ? \
(void) strcpy(string, YesString) : \
(void) strcpy(string, NoString)) \
static char YesString[] = "yes";
static char NoString[] = "no";
/*
* If Setup() succeeds, flag same. Also, we don't need a file requester
* on receive.
*/
#define SUCCESS (XPRS_SUCCESS | XPRS_NORECREQ)
extern char _H1_org, _H1_end, _H2_org, _H2_end; /* Data segment pointers */
static void NewDataSeg(void *);
#pragma regcall(NewDataSeg(a0))
static SetupVars *
InitData(struct XPR_IO *IO) {
SetupVars *sv;
/*
* Allocate memory for file name buffer and options if first call. Also
* allocate user's data segment and point us at it.
*/
if ((sv = IO->xpr_data) == NULL) {
if ((sv = (SetupVars *) malloc(sizeof(SetupVars))) == NULL)
return NULL;
*sv = Defaults;
if ((sv->DataSeg = malloc(&_H2_end - &_H1_org + 4)) == NULL) {
free(sv);
return NULL;
}
memcpy(sv->DataSeg, &_H1_org, &_H2_end - &_H1_org + 4);
IO->xpr_data = sv;
}
NewDataSeg(sv->DataSeg);
return(sv);
}
long
XProtocolSetup(IO)
struct XPR_IO *IO;
{
long (*xoptions) ();
#define NOPTS 10
struct xpr_option opt[NOPTS], *popt[NOPTS];
#define MAXSTRING 6
char ValueStrings[NOPTS][MAXSTRING];
long status;
int i, j;
char buf[256];
SetupVars *sv, tempvar;
if ((sv = InitData(IO)) == NULL)
return (XPRS_FAILURE);
if ((xupdate = IO->xpr_update) == NULL)
return (XPRS_FAILURE);
if ((xgets = IO->xpr_gets) == NULL)
return (XPRS_FAILURE);
tempvar = *sv;
/*
* In order to use xpr_options, we must have all of the three conditions
* which follow true. Otherwise, either IO->xpr_filename is non-NULL, in
* which case we assume it contains a setup string, or there is no
* xpr_options, in which case we use xpr_gets to retrieve a setup string.
*/
if (IO->xpr_filename == NULL &&
IO->xpr_extension >= 1 &&
(xoptions = IO->xpr_options) != NULL) {
/*
* I use a counter, i, here, so that I can stick in more options
* without needing to change a lot of numbers. I can also skip
* options dynamically, as in Text below.
*/
i = 0;
/* Announce us. */
opt[i].xpro_description = "Kermit Commands " VSTRING;
opt[i].xpro_type = XPRO_HEADER;
opt[i].xpro_value = NULL;
opt[i].xpro_length = 0;
i++;
/*
* First, do the Kermit server command items.
*/
opt[i].xpro_description = "Kermit FINISH";
opt[i].xpro_type = XPRO_COMMAND;
opt[i].xpro_value = NULL;
opt[i].xpro_length = 0;
i++;
opt[i].xpro_description = "Kermit BYE";
opt[i].xpro_type = XPRO_COMMAND;
opt[i].xpro_value = NULL;
opt[i].xpro_length = 0;
i++;
opt[i].xpro_description = "Kermit CD";
opt[i].xpro_type = XPRO_COMMPAR;
buf[0] = '\0';
opt[i].xpro_value = buf; /* Use buf to hold dir name. */
opt[i].xpro_length = sizeof(buf) - 1;
i++;
opt[i].xpro_description = "Kermit Options";
opt[i].xpro_type = XPRO_COMMAND;
opt[i].xpro_value = NULL;
opt[i].xpro_length = 0;
i++;
/* show requester after loading pointers */
for (j = 0; j < i; j++)
popt[j] = &opt[j];
status = callda(xoptions, (long) i, popt);
/* check returned value */
if (status == -1L)
return XPRS_FAILURE;
/* Check returned value to see what we are to do. */
i = 1;
if (status & (1L << i))
return (KermitFinish(IO) ? SUCCESS : XPRS_FAILURE);
i++;
if (status & (1L << i))
return (KermitBye(IO) ? SUCCESS : XPRS_FAILURE);
i++;
if (status & (1L << i))
return (KermitCd(IO, opt[i].xpro_value) ? SUCCESS : XPRS_FAILURE);
/* If we get to this point, we are to set options. */
i = 0; /* Start over. */
opt[i].xpro_description = "Kermit Options " VSTRING;
opt[i].xpro_type = XPRO_HEADER;
opt[i].xpro_value = NULL;
opt[i].xpro_length = 0;
i++;
/* Convert filename */
opt[i].xpro_description = "Convert Filename";
opt[i].xpro_type = XPRO_BOOLEAN;
XprSet(tempvar.ConvertFlag, ValueStrings[i]);
opt[i].xpro_value = ValueStrings[i];
opt[i].xpro_length = MAXSTRING;
i++;
/* Partial file keep */
opt[i].xpro_description = "Keep Incomplete";
opt[i].xpro_type = XPRO_BOOLEAN;
XprSet(tempvar.KeepFlag, ValueStrings[i]);
opt[i].xpro_value = ValueStrings[i];
opt[i].xpro_length = MAXSTRING;
i++;
/* host is server */
opt[i].xpro_description = "Host Server";
opt[i].xpro_type = XPRO_BOOLEAN;
XprSet(tempvar.GetFlag, ValueStrings[i]);
opt[i].xpro_value = ValueStrings[i];
opt[i].xpro_length = MAXSTRING;
i++;
/*
* file type -- only show this if xpr_finfo not present, or returns
* error when we try to get the file type.
*/
if ((xfinfo = IO->xpr_finfo) == NULL ||
(tempvar.TextFlag = (int) (callad(xfinfo, "", 2L))) == 0) {
tempvar.TextFlag = -1; /* Flag xfinfo failed. */
opt[i].xpro_description = "Text File";
opt[i].xpro_type = XPRO_BOOLEAN;
XprSet(tempvar.TextFlag, ValueStrings[i]);
opt[i].xpro_value = ValueStrings[i];
opt[i].xpro_length = MAXSTRING;
i++;
} else
/*
* Switch to 0 for binary, 1 for text; xpr_finfo returns 1 for
* binary, 2 for text.
*/
tempvar.TextFlag -= 1;
/* Packet size */
opt[i].xpro_description = "Packet Size";
opt[i].xpro_type = XPRO_LONG;
(void) sprintf(ValueStrings[i], "%-d", tempvar.MaxPacket);
opt[i].xpro_value = ValueStrings[i];
opt[i].xpro_length = MAXSTRING;
i++;
/* Block Check type */
opt[i].xpro_description = "Block Check (1, 2, 3)";
opt[i].xpro_type = XPRO_LONG;
(void) sprintf(ValueStrings[i], "%-d", tempvar.BlockCheckType);
opt[i].xpro_value = ValueStrings[i];
opt[i].xpro_length = MAXSTRING;
i++;
/* Retry Limit */
opt[i].xpro_description = "Maximum Retries";
opt[i].xpro_type = XPRO_LONG;
(void) sprintf(ValueStrings[i], "%-d", tempvar.RetryLimit);
opt[i].xpro_value = ValueStrings[i];
opt[i].xpro_length = MAXSTRING;
i++;
/* Timeout */
opt[i].xpro_description = "Timeout (seconds)";
opt[i].xpro_type = XPRO_LONG;
(void) sprintf(ValueStrings[i], "%-d", tempvar.Timeout);
opt[i].xpro_value = ValueStrings[i];
opt[i].xpro_length = MAXSTRING;
i++;
/* show requester after loading pointers */
for (j = 0; j < i; j++)
popt[j] = &opt[j];
/* show requester */
status = callda(xoptions, (long) i, popt);
/* check returned value */
if (status == -1L)
return XPRS_FAILURE;
i = 1; /* Skip header */
if (status & (1L << i))
tempvar.ConvertFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
i++;
if (status & (1L << i))
tempvar.KeepFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
i++;
if (status & (1L << i))
tempvar.GetFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
i++;
if (xfinfo == NULL || tempvar.TextFlag == -1) {
if (status & (1L << i))
tempvar.TextFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
i++;
}
if (status & (1L << i))
tempvar.MaxPacket = atoi(opt[i].xpro_value);
i++;
if (status & (1L << i))
tempvar.BlockCheckType = atoi(opt[i].xpro_value);
i++;
if (status & (1L << i))
tempvar.RetryLimit = atoi(opt[i].xpro_value);
i++;
if (status & (1L << i))
tempvar.Timeout = atoi(opt[i].xpro_value);
} else {
if (IO->xpr_filename != NULL)
strcpy(buf, IO->xpr_filename); /* Save setup string */
else { /* Prompt for command/options string */
sprintf(buf, "OC%c,G%c,K%c,T%c,P%d,B%d,R%d,O%d",
tempvar.ConvertFlag ? 'Y' : 'N',
tempvar.GetFlag ? 'Y' : 'N', tempvar.KeepFlag ? 'Y' : 'N',
tempvar.TextFlag ? 'Y' : 'N', tempvar.MaxPacket,
tempvar.BlockCheckType, tempvar.RetryLimit, tempvar.Timeout);
if (callaa(xgets, "Kermit Options", buf) == 0)
return XPRS_FAILURE; /* Failed to set up? */
}
(void) strupr(buf);
switch (buf[0]) {
case 'F':
return (KermitFinish(IO) ? SUCCESS : XPRS_FAILURE);
case 'B':
return (KermitBye(IO) ? SUCCESS : XPRS_FAILURE);
case 'C':
return (KermitCd(IO, buf + 1) ? SUCCESS : XPRS_FAILURE);
case 'O':
if (SetupFromString(IO, buf, &tempvar) == 0)
return XPRS_FAILURE;
break;
case '\0':
break;
default:
ioerr(IO, "Unrecognized XPR Kermit setup string");
break;
}
}
*sv = tempvar; /* Copy setups into safe place. */
/*
* Return success and inform caller that we don't need a requester for
* receive.
*/
return SUCCESS;
}
static char Delimiters[] = " \t\r\n,";
int
SetupFromString(IO, s, sv)
struct XPR_IO *IO;
char *s;
SetupVars *sv;
{
char *p;
char errbuf[50];
if (*s != 'O')
return 0; /* Options string must start with O. */
s++; /* Skip leading O. */
/*
* Hunt for options with strtok. We allow whitespace and commas to
* separate options.
*/
for (p = strtok(s, Delimiters); p != NULL; p = strtok(NULL, Delimiters)) {
switch (*p++) { /* Auto-increment to option */
case 'C': /* Case conversion. */
if (*p == 'Y' || *p == 'N')
sv->ConvertFlag = (*p == 'Y');
else
ioerr(IO, "Illegal C option format (must be Y or N)");
break;
case 'G': /* Get files (Host server) */
if (*p == 'Y' || *p == 'N')
sv->GetFlag = (*p == 'Y');
else
ioerr(IO, "Illegal G option format (must be Y or N)");
break;
case 'K': /* Keep incomplete file */
if (*p == 'Y' || *p == 'N')
sv->KeepFlag = (*p == 'Y');
else
ioerr(IO, "Illegal K option format (must be Y or N)");
break;
case 'T': /* Text file */
if (*p == 'Y' || *p == 'N')
sv->TextFlag = (*p == 'Y');
else
ioerr(IO, "Illegal T option format (must be Y or N)");
break;
case 'P': /* Maximum packet length */
sv->MaxPacket = atoi(p);
break;
case 'B': /* Block check type. */
sv->BlockCheckType = atoi(p);
break;
case 'R': /* Retry limit */
sv->RetryLimit = atoi(p);
break;
case 'O': /* Timeout */
sv->Timeout = atoi(p);
break;
default:
sprintf(errbuf, "Illegal XPR Kermit option: %c", p[-1]);
ioerr(IO, errbuf);
break;
}
}
return 1;
}
/**
*
* Cleanup
*
**/
long
XProtocolCleanup(IO)
struct XPR_IO *IO;
{
if (((SetupVars *)IO->xpr_data)->DataSeg)
free(((SetupVars *)IO->xpr_data)->DataSeg);
if (IO->xpr_data)
free(IO->xpr_data);
IO->xpr_data = NULL;
return (1L);
}
int
XPRParity(IO)
struct XPR_IO *IO;
{
long (*xsetserial) ();
long status;
/* check out parity */
if ((xsetserial = IO->xpr_setserial) != NULL) {
status = calld(xsetserial, -1L);
if (status & 0x00000001L)
return 1;
else
return 0;
} else
return 0; /* Assume no parity if can't tell. */
}
void
XPRLong(IO, i)
struct XPR_IO *IO;
long i;
{
struct XPR_UPDATE xpru;
char locbuf[80];
if ((xupdate = IO->xpr_update) == NULL)
return;
/* debug: show long value */
xpru.xpru_updatemask = XPRU_MSG;
sprintf(locbuf, "%lx", i);
xpru.xpru_msg = &locbuf[0];
(void) calla(xupdate, &xpru);
}
/*
* Copy setup variables into the local copies. If there are none, then
* simply copy the defaults.
*/
static SetupVars *
setup(IO)
struct XPR_IO *IO;
{
register SetupVars *Current;
if ((Current = InitData(IO)) == NULL)
return NULL;
/*
* These are the call-backs we need. If any of them isn't provided, quit.
* Could do some error reporting if at least xupdate is there.
*/
if ((xupdate = IO->xpr_update) == NULL)
return (0L);
if ((xswrite = IO->xpr_swrite) == NULL)
return (0L);
if ((xfopen = IO->xpr_fopen) == NULL)
return (0L);
if ((xfclose = IO->xpr_fclose) == NULL)
return (0L);
if ((xfread = IO->xpr_fread) == NULL)
return (0L);
if ((xsread = IO->xpr_sread) == NULL)
return (0L);
if ((xchkabort = IO->xpr_chkabort) == NULL)
return (0L);
if ((xfnext = IO->xpr_fnext) == NULL)
return (0L);
if ((xffirst = IO->xpr_ffirst) == NULL)
return (0L);
if ((xsflush = IO->xpr_sflush) == NULL)
return (0L);
if ((xfwrite = IO->xpr_fwrite) == NULL)
return (0L);
if ((xgets = IO->xpr_gets) == NULL)
return (0L);
/*
* Here are callbacks we can do without.
*/
xchkmisc = IO->xpr_chkmisc;
if (IO->xpr_extension >= 2)
xunlink = IO->xpr_unlink;
else
xunlink = NULL;
if (IO->xpr_extension >= 3)
xsquery = IO->xpr_squery;
else
xsquery = NULL;
xfinfo = IO->xpr_finfo;
parity = Current->ParityFlag = XPRParity(IO);
text = Current->TextFlag;
convert = Current->ConvertFlag;
urpsiz = Current->MaxPacket;
bctr = Current->BlockCheckType;
limit = Current->RetryLimit;
rtimo = Current->Timeout;
getfile = Current->GetFlag;
keep = Current->KeepFlag;
return Current;
}
/*
* Set the current context's data segment (small model) to the value
* in DataSeg. Uses (undocumented) feature of compiler which allows
* access to variables by name between #asm ... #endasm if preceded
* by double percent sign.
*/
void
NewDataSeg(void *DataSeg) {
#ifndef _lint
;
#asm
movea.l %%DataSeg,a4
add.l #32766,a4
#endasm
#endif
}
/*
* Have the comm program display an error message for us, using a temporary
* XPR_UPDATE structure; used to display errors before Vars gets allocated
*/
void
ioerr(IO, msg)
struct XPR_IO *IO;
char *msg;
{
struct XPR_UPDATE xpru;
if ((xupdate = IO->xpr_update) != NULL) {
xpru.xpru_updatemask = XPRU_ERRORMSG;
xpru.xpru_errormsg = msg;
(void) calla(xupdate, &xpru);
}
}
/*
* Simple, re-entrant versions of malloc() and free to replace the ones in
* the Aztec C libraries. The only reason to use these instead of AllocMem()
* is that these remember the size of the stuff allocated, and we don't
* have to rewrite the system-independent Kermit code in terms of AllocMem().
*/
void *malloc(size_t n)
{
long *p;
if ((p = AllocMem((long)(n + sizeof(size_t)), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
return NULL;
p[0] = (long)(n + sizeof(size_t));
return (&p[1]);
}
void free(void *p)
{
long *s = p;
FreeMem(&s[-1], s[-1]);
}
/**
*
* The following functions setup the proper registers for the call-back
* functions.
*
**/
#ifndef _lint
#asm
public _callad
_callad:
movea.l 8(sp),a0 ; Second argument goes in a0
move.l 12(sp),d0 ; Third argument goes in d0
/*
* Now this is a trick to avoid using another register.
* Charlie taught me this...
*/
move.l 4(sp),-(sp) ; First argument is function
rts
public _calladda
_calladda:
movea.l 8(sp),a0 ; Second argument goes in a0
move.l 12(sp),d0 ; Third argument goes in d0
move.l 16(sp),d1 ; Fourth argument goes in d1
movea.l 20(sp),a1 ; Fifth argument goes in a1
move.l 4(sp),-(sp) ; First argument is function
rts
public _calldaa
_calldaa:
move.l 8(sp),d0 ; Second argument goes in d0
movea.l 12(sp),a0 ; Third argument goes in a0
movea.l 16(sp),a1 ; Fourth argument goes in a1
move.l 4(sp),-(sp) ; First argument is function
rts
public _calla
_calla:
movea.l 8(sp),a0 ; Second argument goes in a0
move.l 4(sp),-(sp) ; First argument is function
rts
public _calld
_calld:
move.l 8(sp),d0 ; Second argument goes in d0
move.l 4(sp),-(sp) ; First argument is function
rts
public _callaa
_callaa:
movea.l 8(sp),a0 ; Second argument goes in a0
movea.l 12(sp),a1 ; Third argument goes in a1
move.l 4(sp),-(sp) ; First argument is function
rts
public _callda
_callda:
move.l 8(sp),d0 ; Second argument goes in d0
movea.l 12(sp),a0 ; Third argument goes in a0
move.l 4(sp),-(sp) ; First argument is function
rts
public _calladd
_calladd:
movea.l 8(sp),a0 ; Second argument goes in a0
move.l 12(sp),d0 ; Third argument goes in d0
move.l 16(sp),d1 ; Fourth argument goes in d1
move.l 4(sp),-(sp) ; First argument is function
rts
#endasm
/*
* Could have added any other functions needed for other call-backs.
* Could have written a fancier single one... Could've...
*/
#endif